package cc.sunni.sell.service.impl;

import cc.sunni.sell.dao.OrderMasterDao;
import cc.sunni.sell.dto.CartDto;
import cc.sunni.sell.dto.OrderDto;
import cc.sunni.sell.entity.OrderDetail;
import cc.sunni.sell.entity.OrderMaster;
import cc.sunni.sell.entity.ProductInfo;
import cc.sunni.sell.enums.ResultEnum;
import cc.sunni.sell.enums.SellEnums;
import cc.sunni.sell.exception.RRException;
import cc.sunni.sell.service.*;
import cc.sunni.sell.utils.PageUtils;
import cc.sunni.sell.utils.Query;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service("orderMasterService")
public class OrderMasterServiceImpl extends ServiceImpl<OrderMasterDao, OrderMaster> implements OrderMasterService {
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private PayService payService;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private PushMessageService pushMessageService;

    @Override
    @Transactional
    public String create(OrderDto orderDto) {
        List<OrderDetail> orderDetailList = orderDto.getOrderDetailList();
        if (CollUtil.isEmpty(orderDetailList)) {
            throw new RRException(ResultEnum.PARAM_ERROR);
        }
        String orderId = snowflake.nextIdStr();
        // 计算总价
        BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO);
        for (OrderDetail orderDetail : orderDetailList) {
            ProductInfo productInfo = productInfoService.getById(orderDetail.getProductId());
            if (productInfo == null) {
                throw new RRException(ResultEnum.PRODUCT_NOT_EXIST);
            }
            orderAmount = productInfo.getProductPrice().multiply(new BigDecimal(orderDetail.getProductQuantity())).add(orderAmount);

            BeanUtils.copyProperties(productInfo, orderDetail);
            orderDetail.setOrderId(orderId);
            orderDetailService.save(orderDetail);
        }

        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDto, orderMaster);
        orderMaster.setOrderId(orderId);
        orderMaster.setOrderAmount(orderAmount);
        this.save(orderMaster);

        // 减库存
        List<CartDto> cartDtos = orderDetailList.stream().map(e -> new CartDto(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList());
        productInfoService.decrStock(cartDtos);
        return orderId;
    }

    @Override
    public OrderDto findOne(String orderId) {
        OrderMaster orderMaster = this.baseMapper.selectById(orderId);
        if (orderMaster == null) {
            throw new RRException(ResultEnum.ORDER_NOT_EXIST);
        }
        List<OrderDetail> orderDetails = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderId));
        if (CollectionUtil.isEmpty(orderDetails)) {
            throw new RRException(ResultEnum.ORDERDETAIL_NOT_EXIST);
        }
        OrderDto orderDto = new OrderDto();
        BeanUtils.copyProperties(orderMaster, orderDto);
        orderDto.setOrderDetailList(orderDetails);
        setStatusCN(orderDto);
        return orderDto;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderMaster> page = this.page(
                new Query<OrderMaster>().getPage(params),
                // 拼接查询条件
                new LambdaQueryWrapper<OrderMaster>().eq(params.get("openid") != null, OrderMaster::getBuyerOpenid, params.get("openid"))
        );
        List<OrderMaster> orderMasters = page.getRecords();
        List<OrderDto> orderDtos = orderMasters.stream().map(e -> {
            OrderDto orderDto = new OrderDto();
            BeanUtils.copyProperties(e, orderDto);
            setStatusCN(orderDto);
            return orderDto;
        }).collect(Collectors.toList());

        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(orderDtos);
        return pageUtils;
    }

    @Override
    @Transactional
    public void cancel(OrderDto orderDto) {
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDto, orderMaster);
        if (!orderMaster.getOrderStatus().equals(SellEnums.OrderStatusEnum.NEW.getCode())) {
            throw new RRException(ResultEnum.ORDER_STATUS_ERROR);
        }
        orderMaster.setOrderStatus(SellEnums.OrderStatusEnum.CANCEL.getCode());
        this.baseMapper.updateById(orderMaster);

        // 反还库存
        List<CartDto> cartDtos = orderDto.getOrderDetailList().stream().map(e -> new CartDto(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList());
        productInfoService.incrStock(cartDtos);

        // 退款
        if (orderDto.getPayStatus().equals(SellEnums.PayStatusEnum.SUCCESS.getCode())) {
            payService.refund(orderDto);
        }
    }

    @Override
    @Transactional
    public void finish(OrderDto orderDto) {
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDto, orderMaster);
        if (!orderMaster.getOrderStatus().equals(SellEnums.OrderStatusEnum.NEW.getCode())) {
            throw new RRException(ResultEnum.ORDER_STATUS_ERROR);
        }
        orderMaster.setOrderStatus(SellEnums.OrderStatusEnum.FINISHED.getCode());
        this.baseMapper.updateById(orderMaster);

        pushMessageService.orderStatus(orderDto);
    }

    @Override
    @Transactional
    public void pay(OrderDto orderDto) {
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDto, orderMaster);
        if (!orderMaster.getOrderStatus().equals(SellEnums.OrderStatusEnum.NEW.getCode())) {
            throw new RRException(ResultEnum.ORDER_STATUS_ERROR);
        }

        if (!orderMaster.getPayStatus().equals(SellEnums.PayStatusEnum.WAIT.getCode())) {
            throw new RRException(ResultEnum.ORDER_PAY_STATUS_ERROR);
        }

        orderMaster.setPayStatus(SellEnums.PayStatusEnum.SUCCESS.getCode());
        this.baseMapper.updateById(orderMaster);
    }

    private void setStatusCN(OrderDto orderDto) {
        SellEnums.OrderStatusEnum orderStatusEnum = EnumUtil.likeValueOf(SellEnums.OrderStatusEnum.class, orderDto.getOrderStatus());
        orderDto.setOrderStatusCN(orderStatusEnum.getMessage());
        SellEnums.PayStatusEnum payStatusEnum = EnumUtil.likeValueOf(SellEnums.PayStatusEnum.class, orderDto.getPayStatus());
        orderDto.setPayStatusCN(payStatusEnum.getMessage());
    }

}